#ifndef _BYTEBUFFER_H_
#define _BYTEBUFFER_H_

#include "Common.h"

#include <malloc.h>
#include <string.h>
#include <string>
using namespace std;

/**
 * @class ByteBuffer
 *
 * the underlying buffer may grow in case of lack of buffer space.
 * the growth is specified by a fixed size in bytes
 */
class ByteBuffer
{
public:
    /**
     * ctor with init size and growth
     *
     * @param size      init buffer size in bytes
     *                  0 bytes by default (no data space)
     * @param growth    growth in bytes.
     *                  0 bytes by default (not growable)
     */
    ByteBuffer(uint32 size = 0, uint32 growth = 0)
        : _data(0)
        , _size(size)
        , _rd_ptr(0)
        , _wr_ptr(0)
        , _growth(growth)
    {
        if (_size > 0) _data = (char *)::malloc(_size);
    }

    /// destructor
    virtual ~ByteBuffer()
    {
        if ( _data ) ::free( _data );
    }

public:
    inline char *data() const
    {
        return _data;
    }

    inline char *rd_ptr() const
    {
        return _data + _rd_ptr;
    }

    inline void rd_ptr(char *ptr)
    {
        _rd_ptr = (uint32)(ptr - _data);
    }

    inline void rd_ptr(uint32 n)
    {
        _rd_ptr += n;
    }

    inline char *wr_ptr() const
    {
        return _data + _wr_ptr;
    }

    inline void wr_ptr(char *ptr)
    {
        _wr_ptr = (uint32)(ptr - _data);
    }

    inline void wr_ptr(uint32 n)
    {
        _wr_ptr += n;
    }

    /// return a pointer to the nth byte
    inline char *ptr(uint32 n) const
    {
        return n < _size ? _data + n : 0;
    }

    /// return buffer capacity
    inline uint32 size() const
    {
        return _size;
    }

    /// equivalent to avail() == 0
    inline int empty() const
    {
        return _rd_ptr == _wr_ptr;
    }

    /// available for reading
    inline uint32 avail() const
    {
        return _wr_ptr - _rd_ptr;
    }

    /// free space for writing
    inline uint32 free() const
    {
        return _size - _wr_ptr;
    }

    /// growth accessors
    inline uint32 growth() const
    {
        return _growth;
    }

    inline void growth(uint32 v)
    {
        _growth = v;
    }

    /**
     * read & write
     *
     * @retval return bytes actually read or written
     */
    uint32 read(void *buf, uint32 len);
    uint32 write(const void *buf, uint32 len);

    /// resize the underlying buffer
    inline void resize(uint32 n)
    {
        _data = (char *)realloc(_data, n);
        _size = n;
    }

    inline void reset()
    {
        _rd_ptr = _wr_ptr = 0;
    }

    inline void release()
    {
        delete this;
    }

    /// numeric operators
#define BYTEBUFFER_READ_OPERATOR(type)          \
    inline ByteBuffer& operator >> (type &v)    \
    {                                           \
        this->read(&v, sizeof(type));           \
                                                \
        return *this;                           \
    }

#define BYTEBUFFER_WRITE_OPERATOR(type)             \
    inline ByteBuffer& operator << (const type v)   \
    {                                               \
        this->write(&v, sizeof(type));              \
                                                    \
        return *this;                               \
    }

    /// read operators
    BYTEBUFFER_READ_OPERATOR(int8);
    BYTEBUFFER_READ_OPERATOR(int16);
    BYTEBUFFER_READ_OPERATOR(int32);
    BYTEBUFFER_READ_OPERATOR(int64);

    BYTEBUFFER_READ_OPERATOR(uint8);
    BYTEBUFFER_READ_OPERATOR(uint16);
    BYTEBUFFER_READ_OPERATOR(uint32);
    BYTEBUFFER_READ_OPERATOR(uint64);

    BYTEBUFFER_READ_OPERATOR(float);
    BYTEBUFFER_READ_OPERATOR(double);

    /// write operators
    BYTEBUFFER_WRITE_OPERATOR(int8);
    BYTEBUFFER_WRITE_OPERATOR(int16);
    BYTEBUFFER_WRITE_OPERATOR(int32);
    BYTEBUFFER_WRITE_OPERATOR(int64);

    BYTEBUFFER_WRITE_OPERATOR(uint8);
    BYTEBUFFER_WRITE_OPERATOR(uint16);
    BYTEBUFFER_WRITE_OPERATOR(uint32);
    BYTEBUFFER_WRITE_OPERATOR(uint64);

    BYTEBUFFER_WRITE_OPERATOR(float);
    BYTEBUFFER_WRITE_OPERATOR(double);

    /// string read operator
    ByteBuffer& operator >> (string &str);

    /// string write operator
    inline ByteBuffer& operator << (const char *str)
    {
        this->write(str, (uint32)strlen(str) + 1);
        return *this;
    }

    /// string write operator
    inline ByteBuffer& operator << (const string &str)
    {
        this->write(str.c_str(), (uint32)str.length() + 1);
        return *this;
    }

private:
    /// disable copy ctor
    ByteBuffer(const ByteBuffer &rhs) {}

    /// disable operator =
    ByteBuffer &operator =(const ByteBuffer &rhs) {return *this;}

private:
    char  *_data;
    uint32 _size;
    uint32 _rd_ptr, _wr_ptr;
    uint32 _growth;
};

#endif
